// PdfToolsTestDlg.cpp : implementation file
//

#include "stdafx.h"
#include "PdfToolsTest.h"
#include "PdfToolsTestDlg.h"
#include <cmath>
#include <fstream>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#import "libid:9EFE0FFF-9A5F-4CAF-A6F7-DEEE6C865B6B"


// CPdfToolsTestDlg dialog
DWORD fileSize(const CString &path)
{
	std::ifstream f(path, std::ios::in | std::ios::binary);
	f.seekg(0, std::ios::end);
	return static_cast<DWORD>( f.tellg() );
}



CPdfToolsTestDlg::CPdfToolsTestDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CPdfToolsTestDlg::IDD, pParent)
	, m_sOldPath(_T(""))
	, m_sNewPath(_T(""))
	, m_nModuleVersion(0)
	, m_sSrcPath(_T(""))
	, m_sDstPath(_T(""))
	, m_bPagesFilter(FALSE)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CPdfToolsTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_EDIT_OLD_PATH, m_sOldPath);
	DDX_Text(pDX, IDC_EDIT_NEW_PATH, m_sNewPath);
	DDX_Radio(pDX, IDC_RADIO_OLD, m_nModuleVersion);
	DDX_Text(pDX, IDC_EDIT_SRC_PATH, m_sSrcPath);
	DDX_Text(pDX, IDC_EDIT_DST_PATH, m_sDstPath);
	DDX_Control(pDX, IDC_LIST_ORIG, m_lbSrcFolder);
	DDX_Control(pDX, IDC_LIST_MERGE, m_lbDstFolder);
	DDX_Control(pDX, IDC_LIST_SPLIT, m_lbPages);
	DDX_Control(pDX, IDC_LIST_LOG, m_lbLog);
	DDX_Check(pDX, IDC_FILTER_CHECK, m_bPagesFilter);
}

BEGIN_MESSAGE_MAP(CPdfToolsTestDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_SRC_PATH, &CPdfToolsTestDlg::OnBnClickedButtonSrcPath)
	ON_BN_CLICKED(IDC_RADIO_NEW, &CPdfToolsTestDlg::OnBnClickedRadio)
	ON_BN_CLICKED(IDC_RADIO_OLD, &CPdfToolsTestDlg::OnBnClickedRadio)
	ON_BN_CLICKED(IDC_BUTTON_DST_PATH, &CPdfToolsTestDlg::OnBnClickedButtonDstPath)
	ON_EN_CHANGE(IDC_EDIT_SRC_PATH, &CPdfToolsTestDlg::OnEnChangeEditSrcPath)
	ON_EN_CHANGE(IDC_EDIT_DST_PATH, &CPdfToolsTestDlg::OnEnChangeEditDstPath)
	ON_LBN_DBLCLK(IDC_LIST_ORIG, &CPdfToolsTestDlg::OnLbnDblclkListOrig)
	ON_LBN_DBLCLK(IDC_LIST_SPLIT, &CPdfToolsTestDlg::OnLbnDblclkListSplit)
	ON_LBN_DBLCLK(IDC_LIST_MERGE, &CPdfToolsTestDlg::OnLbnDblclkListMerge)
	ON_BN_CLICKED(IDC_BUTTON_SPLIT, &CPdfToolsTestDlg::OnBnClickedButtonSplit)
	ON_BN_CLICKED(IDC_BUTTON_STOP, &CPdfToolsTestDlg::OnBnClickedButtonStop)
	ON_BN_CLICKED(IDC_BUTTON_MERGE, &CPdfToolsTestDlg::OnBnClickedButtonMerge)
	ON_LBN_SELCHANGE(IDC_LIST_ORIG, &CPdfToolsTestDlg::OnLbnSelchangeListOrig)
	ON_BN_CLICKED(IDC_LOG_BUTTON, &CPdfToolsTestDlg::OnBnClickedLogButton)
END_MESSAGE_MAP()


// CPdfToolsTestDlg message handlers

BOOL CPdfToolsTestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	HMODULE hOldDll = NULL;
	
	if ( (hOldDll = ::GetModuleHandle(_T("PDFTools.dll"))) != FALSE )
	{
		::GetModuleFileName( hOldDll, m_sOldPath.GetBuffer(MAX_PATH), MAX_PATH );
		m_sOldPath.ReleaseBuffer();
	}
	else
		m_sOldPath = _T("Not Found");

	CRegKey regNewDll;
	if (ERROR_SUCCESS == regNewDll.Open(HKEY_CLASSES_ROOT, _T("TypeLib\\{9EFE0FFF-9A5F-4CAF-A6F7-DEEE6C865B6B}\\1.0\\0\\win32"), KEY_READ))
	{
		ULONG length = MAX_PATH;
		regNewDll.QueryStringValue(NULL, m_sNewPath.GetBuffer(MAX_PATH), &length);
		m_sNewPath.ReleaseBuffer();
	}
	else
		m_sNewPath = _T("Not Found");

	m_nModuleVersion = theApp.GetProfileInt(_T("Settings"), _T("ModuleVersion"), 0);

	switch (m_nModuleVersion)
	{
	case 0:
		m_sSrcPath = theApp.GetProfileString(_T("Settings"), _T("OldSrcPath"));
		m_sDstPath = theApp.GetProfileString(_T("Settings"), _T("OldDstPath"));
		break;
	case 1:
		m_sSrcPath = theApp.GetProfileString(_T("Settings"), _T("NewSrcPath"));
		m_sDstPath = theApp.GetProfileString(_T("Settings"), _T("NewDstPath"));
		break;
	}

	UpdateData(FALSE);

	UpdateSrcList();
	UpdatePagesList();
	UpdateDstList();

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CPdfToolsTestDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CPdfToolsTestDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CPdfToolsTestDlg::OnBnClickedButtonSrcPath()
{
	UpdateData();
	CString srcPath;

	BROWSEINFO bi = { 0 };
	bi.hwndOwner		= GetSafeHwnd();
	bi.pszDisplayName	= srcPath.GetBuffer(MAX_PATH);
	bi.ulFlags			= BIF_RETURNONLYFSDIRS;

	ITEMIDLIST* pIDList = SHBrowseForFolder( &bi );
	if( pIDList == NULL )
		return;

	if( ::SHGetPathFromIDList( pIDList, srcPath.GetBuffer(MAX_PATH) ) == TRUE )
	{
		srcPath.ReleaseBuffer();
		m_sSrcPath = srcPath;
		UpdateData(FALSE);

		OnEnChangeEditSrcPath();
		OnEnChangeEditDstPath();
	}
}

void CPdfToolsTestDlg::OnBnClickedRadio()
{
	UpdateData();
	theApp.WriteProfileInt(_T("Settings"), _T("ModuleVersion"), m_nModuleVersion);

	switch (m_nModuleVersion)
	{
	case 0:
		m_sSrcPath = theApp.GetProfileString(_T("Settings"), _T("OldSrcPath"));
		m_sDstPath = theApp.GetProfileString(_T("Settings"), _T("OldDstPath"));
		break;
	case 1:
		m_sSrcPath = theApp.GetProfileString(_T("Settings"), _T("NewSrcPath"));
		m_sDstPath = theApp.GetProfileString(_T("Settings"), _T("NewDstPath"));
		break;
	}

	UpdateData(FALSE);
	UpdateSrcList();
	UpdatePagesList();
	UpdateDstList();
}

void CPdfToolsTestDlg::OnBnClickedButtonDstPath()
{
	UpdateData();
	CString dstPath;

	BROWSEINFO bi = { 0 };
	bi.hwndOwner		= GetSafeHwnd();
	bi.pszDisplayName	= dstPath.GetBuffer(MAX_PATH);
	bi.ulFlags			= BIF_RETURNONLYFSDIRS;

	ITEMIDLIST* pIDList = SHBrowseForFolder( &bi );
	if( pIDList == NULL )
		return;

	if( ::SHGetPathFromIDList( pIDList, dstPath.GetBuffer(MAX_PATH) ) == TRUE )
	{
		dstPath.ReleaseBuffer();
		m_sDstPath = dstPath;
		UpdateData(FALSE);
		OnEnChangeEditDstPath();
	}
}

void CPdfToolsTestDlg::OnEnChangeEditSrcPath()
{
	UpdateData();
	switch (m_nModuleVersion)
	{
	case 0:
		theApp.WriteProfileString(_T("Settings"), _T("OldSrcPath"), m_sSrcPath);
		break;
	case 1:
		theApp.WriteProfileString(_T("Settings"), _T("NewSrcPath"), m_sSrcPath);
		break;
	}
	UpdateSrcList();
}

void CPdfToolsTestDlg::OnEnChangeEditDstPath()
{
	UpdateData();
	switch (m_nModuleVersion)
	{
	case 0:
		theApp.WriteProfileString(_T("Settings"), _T("OldDstPath"), m_sDstPath);
		break;
	case 1:
		theApp.WriteProfileString(_T("Settings"), _T("NewDstPath"), m_sDstPath);
		break;
	}
	UpdateDstList();
}

void CPdfToolsTestDlg::UpdateSrcList()
{
	CString curSel;
	
	if (m_lbSrcFolder.GetCurSel() != -1)
		m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), curSel );

	UpdateData();
	m_lbSrcFolder.ResetContent();
	m_lbSrcFolder.Dir(0, m_sSrcPath + _T("\\*.pdf"));
	m_lbSrcFolder.SelectString(0, curSel);
}

void CPdfToolsTestDlg::UpdatePagesList()
{
	UpdateData();
	m_lbPages.ResetContent();
	if (m_bPagesFilter != FALSE && m_lbSrcFolder.GetCurSel() != -1)
	{
		CString srcFileName;
		m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), srcFileName );
		srcFileName = srcFileName.Left(srcFileName.GetLength() - 4) + _T(".page.*.pdf");
		CPath path(m_sDstPath);
		path.Append(srcFileName);
		m_lbPages.Dir(0, path.m_strPath);
	}
	else
		m_lbPages.Dir(0, m_sDstPath + _T("\\*.pdf"));
}

void CPdfToolsTestDlg::UpdateDstList()
{
	UpdateData();
	m_lbDstFolder.ResetContent();
	if (m_lbSrcFolder.GetCurSel() != -1)
	{
		CString srcFileName;
		m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), srcFileName );
		srcFileName = srcFileName.Left(srcFileName.GetLength() - 4) + _T(".merged.pdf");
		CPath path(m_sDstPath);
		path.Append(srcFileName);
		m_lbDstFolder.Dir(0, path.m_strPath);
	}
}

void CPdfToolsTestDlg::OnLbnDblclkListOrig()
{
	CString srcFileName;
	m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), srcFileName );
	CPath path(m_sSrcPath);
	path.Append(srcFileName);
	::ShellExecute( GetSafeHwnd(), _T("open"), path.m_strPath, 0, 0, SW_NORMAL );
}

void CPdfToolsTestDlg::OnLbnDblclkListSplit()
{
	CString sel;
	m_lbPages.GetText( m_lbPages.GetCurSel(), sel );
	CPath path(m_sDstPath);
	path.Append(sel);
	::ShellExecute( GetSafeHwnd(), _T("open"), path.m_strPath, 0, 0, SW_NORMAL );
}

void CPdfToolsTestDlg::OnLbnDblclkListMerge()
{
	CString sel;
	m_lbDstFolder.GetText( m_lbDstFolder.GetCurSel(), sel );
	CPath path(m_sDstPath);
	path.Append(sel);
	::ShellExecute( GetSafeHwnd(), _T("open"), path.m_strPath, 0, 0, SW_NORMAL );
}

DWORD getDelta(LARGE_INTEGER start, LARGE_INTEGER end)
{
	LARGE_INTEGER freq = { 0 };
	::QueryPerformanceFrequency( &freq );

	double delta = double(end.QuadPart - start.QuadPart) / double(freq.QuadPart);
	return static_cast<DWORD>( floor(1000 * delta + 0.5) );
}


UINT AFX_CDECL SplitThread(LPVOID pv)
{
	CPdfToolsTestDlg *dlg = (CPdfToolsTestDlg*)pv;
	UINT result = 0;
	::CoInitialize(0);

	dlg->GetDlgItem(IDOK)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_SPLIT)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_MERGE)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_NEW)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_OLD)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_SRC_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_DST_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_EDIT_SRC_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_EDIT_DST_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE);

	try
	{
		CString srcFileName;
		dlg->m_lbSrcFolder.GetText( dlg->m_lbSrcFolder.GetCurSel(), srcFileName.GetBuffer(MAX_PATH) );
		srcFileName.ReleaseBuffer();
		CPath srcPath( dlg->m_sSrcPath );
		srcPath.Append( srcFileName );

		LARGE_INTEGER tmBefore = { 0 }, tmAfter = { 0 };
		DWORD tmTotal = 0;

		switch (dlg->m_nModuleVersion)
		{
		case 0:
			{
				::QueryPerformanceCounter( &tmBefore );
				CPdfSplitter splitter;
				splitter.OpenPdf( srcPath.m_strPath, _T(""), FALSE );
				::QueryPerformanceCounter( &tmAfter );

				tmTotal += getDelta( tmBefore, tmAfter );

				CString log;
				log.Format(_T("%s was opened in %d ms, %d bytes"), srcFileName, getDelta( tmBefore, tmAfter ), fileSize(srcPath.m_strPath));
				dlg->AppendLog(log);

				dlg->m_csStopThread.Lock();
				bool bStopThread = dlg->m_bStopThread;
				dlg->m_csStopThread.Unlock();
				
				for (int i = 0, count = splitter.GetPageCount(); !bStopThread && i < count; ++i)
				{	
					CArray<INT, INT> pages;
					pages.Add(i + 1);
					
					CString dstFileName;
					dstFileName.Format(_T("%spage.%.5d.pdf"), srcFileName.Left( srcFileName.GetLength() - 3 ), i);
					CPath dstPath(dlg->m_sDstPath);
					dstPath.Append(dstFileName);

					::QueryPerformanceCounter( &tmBefore );
					splitter.SavePagesToFile(dstPath.m_strPath, &pages);
					::QueryPerformanceCounter( &tmAfter );
					tmTotal += getDelta( tmBefore, tmAfter );

					CString log;
					log.Format(_T("%s was saved in %d ms, %d bytes"), dstFileName, getDelta( tmBefore, tmAfter ), fileSize(dstPath.m_strPath));
					dlg->AppendLog(log);

					dlg->m_lbPages.AddString(dstFileName);

					// =====================================================================

					dlg->m_csStopThread.Lock();
					bStopThread = dlg->m_bStopThread;
					dlg->m_csStopThread.Unlock();
				}

				::QueryPerformanceCounter( &tmBefore );
				splitter.ClosePdf();
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				log.Format(_T("%s was closed in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				log.Format(_T("%s was processed in %d ms"), srcFileName, tmTotal);
				dlg->AppendLog(log);
			}
			break;
		case 1:
			{
				::QueryPerformanceCounter( &tmBefore );
				PdfTools::IPdfSplitterPtr splitter(__uuidof(PdfTools::PdfSplitter));
				splitter->Open( _bstr_t(srcPath.m_strPath), _bstr_t() );
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				CString log;
				log.Format(_T("%s was opened in %d ms, %d bytes"), srcFileName, getDelta( tmBefore, tmAfter ), fileSize(srcPath.m_strPath));
				dlg->AppendLog(log);

				dlg->m_csStopThread.Lock();
				bool bStopThread = dlg->m_bStopThread;
				dlg->m_csStopThread.Unlock();

				for (ULONG i = 0, count = splitter->PageCount; !bStopThread && i < count; ++i)
				{	
					CString dstFileName;
					dstFileName.Format(_T("%spage.%.5d.pdf"), srcFileName.Left( srcFileName.GetLength() - 3 ), i);
					CPath dstPath(dlg->m_sDstPath);
					dstPath.Append(dstFileName);

					::QueryPerformanceCounter( &tmBefore );
					splitter->SavePages(_bstr_t(dstPath.m_strPath), 1, &i);
					::QueryPerformanceCounter( &tmAfter );
					tmTotal += getDelta( tmBefore, tmAfter );

					CString log;
					log.Format(_T("%s was saved in %d ms, %d bytes"), dstFileName, getDelta( tmBefore, tmAfter ), fileSize(dstPath.m_strPath));
					dlg->AppendLog(log);

					dlg->m_lbPages.AddString(dstFileName);

					// =====================================================================

					dlg->m_csStopThread.Lock();
					bStopThread = dlg->m_bStopThread;
					dlg->m_csStopThread.Unlock();
				}

				::QueryPerformanceCounter( &tmBefore );
				splitter->Close();
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				log.Format(_T("%s was closed in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				log.Format(_T("%s was processed in %d ms"), srcFileName, tmTotal);
				dlg->AppendLog(log);
			}
			break;
		}

		dlg->m_pSplitThread = NULL;
		result = 0;
	}
	catch (CException *e)
	{
		CString msg;
		e->GetErrorMessage(msg.GetBuffer(1024), 1024);
		msg.ReleaseBuffer();

		CString log;
		log.Format(_T("ERROR: %s"), msg);
		dlg->AppendLog(log);

		e->Delete();
		result = -1;
	}
	catch (_com_error &e)
	{
		CString log;
		log.Format(_T("ERROR: %s [%s]"), e.ErrorMessage(), (PCTSTR)e.Description() );
		dlg->AppendLog(log);
		result = -1;
	}
	catch (...)
	{
		CString log;
		log.Format(_T("ERROR: DUMB VOVAN MISS POSSIBILITY TO DEREFERENCE NULL POINTER OR DIVIDE BY ZERO!!!"));
		dlg->AppendLog(log);
		result = -1;
	}

	dlg->GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_NEW)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_RADIO_OLD)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_SRC_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_DST_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_EDIT_SRC_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_EDIT_DST_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_MERGE)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_SPLIT)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDOK)->EnableWindow(TRUE);

	::CoUninitialize();
	return result;
}

UINT AFX_CDECL MergeThread(LPVOID pv)
{
	CPdfToolsTestDlg *dlg = (CPdfToolsTestDlg*)pv;
	UINT result = 0;
	::CoInitialize(0);

	dlg->GetDlgItem(IDOK)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_SPLIT)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_MERGE)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_NEW)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_OLD)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_SRC_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_DST_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_EDIT_SRC_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_EDIT_DST_PATH)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE);

	try
	{
		CString srcFileName;
		dlg->m_lbPages.GetText( 0, srcFileName.GetBuffer(MAX_PATH) );
		srcFileName.ReleaseBuffer();
		CPath srcPath( dlg->m_sDstPath );
		srcFileName = srcFileName.Left(srcFileName.GetLength() - 15) + _T(".merged.pdf");
		srcPath.Append( srcFileName );

		LARGE_INTEGER tmBefore = { 0 }, tmAfter = { 0 }; 
		DWORD tmTotal = 0;

		switch (dlg->m_nModuleVersion)
		{
		case 0:
			{
				std::vector<int> selection( dlg->m_lbPages.GetSelCount() );
				dlg->m_lbPages.GetSelItems(selection.size(), &selection[0]);

				::QueryPerformanceCounter( &tmBefore );
				{
					CString dstFileName;
					dlg->m_lbPages.GetText( selection[0], dstFileName.GetBuffer(MAX_PATH) );
					dstFileName.ReleaseBuffer();

					CPath dstPath(dlg->m_sDstPath);
					dstPath.Append(dstFileName);

					::CopyFile( dstPath.m_strPath, srcPath.m_strPath, FALSE );
				}

				CPdfSplitter splitter;
				splitter.OpenPdf( srcPath.m_strPath, _T(""), TRUE );
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				CString log;
				log.Format(_T("%s was opened in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				dlg->m_csStopThread.Lock();
				bool bStopThread = dlg->m_bStopThread;
				dlg->m_csStopThread.Unlock();

				for (int i = 1, count = dlg->m_lbPages.GetSelCount(); !bStopThread && i < count; ++i)
				{	
					CString dstFileName;
					dlg->m_lbPages.GetText( selection[i], dstFileName.GetBuffer(MAX_PATH) );
					dstFileName.ReleaseBuffer();

					CPath dstPath(dlg->m_sDstPath);
					dstPath.Append(dstFileName);

					::QueryPerformanceCounter( &tmBefore );
					splitter.AddPagesFromFile(dstPath.m_strPath, _T(""));
					::QueryPerformanceCounter( &tmAfter );
					tmTotal += getDelta( tmBefore, tmAfter );

					CString log;
					log.Format(_T("%s was appended in %d ms, %d bytes"), dstFileName, getDelta( tmBefore, tmAfter ), fileSize(dstPath.m_strPath));
					dlg->AppendLog(log);

					// =====================================================================

					dlg->m_csStopThread.Lock();
					bStopThread = dlg->m_bStopThread;
					dlg->m_csStopThread.Unlock();
				}

				::QueryPerformanceCounter( &tmBefore );
				splitter.WriteDocFooter();
				splitter.ClosePdf();
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				log.Format(_T("%s was closed in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				log.Format(_T("%s was processed in %d ms, %d bytes"), srcFileName, tmTotal, fileSize(srcPath.m_strPath));
				dlg->AppendLog(log);

				dlg->PostMessage(WM_USER + 1, 0, 0);
			}
			break;
		case 1:
			{
				std::vector<int> selection( dlg->m_lbPages.GetSelCount() );
				dlg->m_lbPages.GetSelItems(selection.size(), &selection[0]);

				::QueryPerformanceCounter( &tmBefore );
				PdfTools::IPdfMergerPtr merger(__uuidof(PdfTools::PdfMerger));
				merger->Open( _bstr_t(srcPath.m_strPath), _bstr_t() );
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				CString log;
				log.Format(_T("%s was opened in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				dlg->m_csStopThread.Lock();
				bool bStopThread = dlg->m_bStopThread;
				dlg->m_csStopThread.Unlock();

				for (int i = 0, count = dlg->m_lbPages.GetSelCount(); !bStopThread && i < count; ++i)
				{	
					CString dstFileName;
					dlg->m_lbPages.GetText( selection[i], dstFileName.GetBuffer(MAX_PATH) );
					dstFileName.ReleaseBuffer();

					CPath dstPath(dlg->m_sDstPath);
					dstPath.Append(dstFileName);

					::QueryPerformanceCounter( &tmBefore );
					merger->Append( _bstr_t(dstPath.m_strPath), _bstr_t() );
					::QueryPerformanceCounter( &tmAfter );
					tmTotal += getDelta( tmBefore, tmAfter );

					CString log;
					log.Format(_T("%s was appended in %d ms, %d bytes"), dstFileName, getDelta( tmBefore, tmAfter ), fileSize(dstPath.m_strPath));
					dlg->AppendLog(log);

					// =====================================================================

					dlg->m_csStopThread.Lock();
					bStopThread = dlg->m_bStopThread;
					dlg->m_csStopThread.Unlock();
				}

				::QueryPerformanceCounter( &tmBefore );
				merger->Close();
				::QueryPerformanceCounter( &tmAfter );
				tmTotal += getDelta( tmBefore, tmAfter );

				log.Format(_T("%s was closed in %d ms"), srcFileName, getDelta( tmBefore, tmAfter ));
				dlg->AppendLog(log);

				log.Format(_T("%s was processed in %d ms, %d bytes"), srcFileName, tmTotal, fileSize(srcPath.m_strPath));
				dlg->AppendLog(log);

				dlg->PostMessage(WM_USER + 1, 0, 0);
			}
			break;
		}

		dlg->m_pMergeThread = NULL;
		result = 0;
	}
	catch (CException *e)
	{
		CString msg;
		e->GetErrorMessage(msg.GetBuffer(1024), 1024);
		msg.ReleaseBuffer();

		CString log;
		log.Format(_T("ERROR: %s"), msg);
		dlg->AppendLog(log);

		e->Delete();
		result = -1;
	}
	catch (_com_error &e)
	{
		CString log;
		log.Format(_T("ERROR: %s [%s]"), e.ErrorMessage(), (PCTSTR)e.Description() );
		dlg->AppendLog(log);
		result = -1;
	}
	catch (...)
	{
		CString log;
		log.Format(_T("ERROR: DUMB VOVAN MISS POSSIBILITY TO DEREFERENCE NULL POINTER OR DIVIDE BY ZERO!!!"));
		dlg->AppendLog(log);
		result = -1;
	}

	dlg->GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);
	dlg->GetDlgItem(IDC_RADIO_NEW)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_RADIO_OLD)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_SRC_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_DST_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_EDIT_SRC_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_EDIT_DST_PATH)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_MERGE)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDC_BUTTON_SPLIT)->EnableWindow(TRUE);
	dlg->GetDlgItem(IDOK)->EnableWindow(TRUE);

	::CoUninitialize();
	return result;
}

void CPdfToolsTestDlg::OnBnClickedButtonSplit()
{
	if (m_lbSrcFolder.GetCurSel() != -1)
	{
		m_bStopThread = false;
		m_lbLog.ResetContent();
		m_lbPages.ResetContent();

		CString srcFileName;
		m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), srcFileName );
		CPath srcPath( m_sSrcPath );
		srcPath.Append( srcFileName );

		AppendLog(_T("************************************************"), false);
		AppendLog(_T("*                  SPLITTING                   *"), false);
		AppendLog(_T("************************************************"), false);

		CTime tm = CTime::GetCurrentTime();
		CString msg = tm.Format(_T("Time Stamp : %H:%M:%S [%B %d, %Y]"));
		AppendLog(msg, false);
		msg.Format(_T("Module Path: %s"), m_nModuleVersion == 0 ? m_sOldPath : m_sNewPath);
		AppendLog(msg, false);
		msg.Format(_T("Source File: %s"), srcPath.m_strPath);
		AppendLog(msg, false);
		msg.Format(_T("Target Path: %s"), m_sDstPath);
		AppendLog(msg, false);
		AppendLog(_T(""), false);

		m_pSplitThread = ::AfxBeginThread(SplitThread, this);
	}
}

void CPdfToolsTestDlg::OnBnClickedButtonStop()
{
	CSingleLock lock( &m_csStopThread );
	m_bStopThread = true;
}

BOOL CPdfToolsTestDlg::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	if (message == WM_USER + 1)
		UpdateDstList();

	return CDialog::OnWndMsg(message, wParam, lParam, pResult);
}

void CPdfToolsTestDlg::OnBnClickedButtonMerge()
{
	if (m_lbPages.GetSelCount() > 0)
	{
		m_bStopThread = false;
		m_lbLog.ResetContent();

		CString dstFileName;
		m_lbSrcFolder.GetText( m_lbSrcFolder.GetCurSel(), dstFileName );
		CPath dstPath( m_sDstPath );
		dstPath.Append( dstFileName.Left(dstFileName.GetLength() - 4) + _T(".merged.pdf") );

		AppendLog(_T("************************************************"), false);
		AppendLog(_T("*                   MERGING                    *"), false);
		AppendLog(_T("************************************************"), false);

		CTime tm = CTime::GetCurrentTime();
		CString msg = tm.Format(_T("Time Stamp : %H:%M:%S [%B %d, %Y]"));
		AppendLog(msg, false);
		msg.Format(_T("Module Path: %s"), m_nModuleVersion == 0 ? m_sOldPath : m_sNewPath);
		AppendLog(msg, false);
		msg.Format(_T("Target File: %s"), dstPath.m_strPath);
		AppendLog(msg, false);
		AppendLog(_T(""), false);

		m_pMergeThread = ::AfxBeginThread(MergeThread, this);
	}
}

void CPdfToolsTestDlg::OnLbnSelchangeListOrig()
{
	UpdatePagesList();
	UpdateDstList();
}

void CPdfToolsTestDlg::AppendLog(const CString &msg, bool display)
{
	if (display)
	{
		m_lbLog.InsertString(-1, msg);
		m_lbLog.SetCurSel( m_lbLog.GetCount() - 1 );
	}

	std::ofstream log("log.txt", std::ios::out | std::ios::app);
	log << msg << std::endl;
}
void CPdfToolsTestDlg::OnBnClickedLogButton()
{
	::ShellExecute( GetSafeHwnd(), _T("open"), _T("log.txt"), 0, 0, SW_NORMAL );
}
